﻿using Microsoft.AspNetCore.Http;
using Microsoft.IdentityModel.Tokens;
using MiniExcelLibs;
using MiniExcelLibs.OpenXml;
using MySqlX.XDevAPI.Common;
using NewLife;
using NewLife.Serialization;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Data;
using System.Dynamic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using XCode;
using XCode.Configuration;
using Zdap.Common;
using Zdap.Common.AutoMapper;
using static Zdap.XCode.Service.CommonService;

namespace Zdap.XCode.Service
{
    /// <summary>
    /// 更改数据
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TDto"></typeparam>
    public abstract class BaseService<TEntity, TDto> : BaseService<TEntity, TDto, TDto> where TDto : class where TEntity : Entity<TEntity>, new()
    {
    }

    /// <summary>
    /// 更改数据
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <typeparam name="TDto"></typeparam>
    /// <typeparam name="TSeachDto"></typeparam>
    public abstract class BaseService<TEntity, TDto, TSeachDto> : SearchServiceBase<TEntity, TSeachDto>, IServiceBase<TDto>
        where TDto : class where TSeachDto : class where TEntity : Entity<TEntity>, new()
    {
        /// <summary>
        /// 添加对象参数校验
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        protected virtual async ValueTask<ResponseContext<bool>> AddValidate(TDto dto)
        {
            return await Task.FromResult(new ResponseContext<bool>(true));
        }

        /// <summary>
        /// 修改对象参数校验
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        protected virtual async ValueTask<ResponseContext<bool>> UpdateValidate(TDto dto)
        {
            return await Task.FromResult(new ResponseContext<bool>(true));
        }

        /// <summary>
        /// 保存
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public virtual async ValueTask<ResponseContext<long>> Save(TDto dto, UserTicket user)
        {
            var result = new ResponseContext<long>();
            long id = 0;
            if (dto == null) return new ResponseContext<long> { Data = id };
            var type = dto.GetType();
            var pi = type.GetProperties().FirstOrDefault(p => p.Name.Equals("Id", StringComparison.OrdinalIgnoreCase));

            if (pi != null)
            {
                id = pi.GetValue(dto).ToLong();
            }
            //LoadJsonFields(dto);
            if (id == 0)
            {
                result = await Add(dto, user);
            }
            else
            {
                var result2 = await Update(dto, user);
                if (!result2.IsSuccess)
                {
                    return result.SetError(result2);
                }
                result.Data = id;
            }
            return result;
        }

        /// <summary>
        /// 批量保存，返回 Id 列表
        /// </summary>
        public virtual async ValueTask<ResponseContext<List<long>>> BatchSave(SavaListModel<TDto> model, UserTicket currentUser)
        {
            var result = new ResponseContext<List<long>>();

            if (model.Dtos == null || model.Dtos.Count == 0)
                return result;

            var ids = new List<long>();
            var entities = new List<TEntity>();
            foreach (var item in model.Dtos)
            {
                long id = GetId(item);
                if (id == 0)//新增
                {
                    var check = await AddValidate(item);
                    if (!check.IsSuccess)
                    {
                        ids.Add(0L);
                        continue;
                    }
                }
                else//修改
                {
                    var check = await UpdateValidate(item);
                    if (!check.IsSuccess)
                        return result.SetError(check);
                }

                var entity = item.MapTo<TEntity>();

                // 处理dto JOSN转string保存
                if (CommonService.IsJsonField(item))
                {
                    CommonService.LoadFieldsJsonCovertString(entity, item);
                }

                ids.Add(SetCommonProperty(entity, currentUser));
                entities.Add(entity);
            }

            var dataColumn = CommonService.GetEntityDataColumn<TEntity>();

            // 插入更新，存在更新，不存在插入
            if (entities.Count > 0)
            {
                int count = entities.Upsert(dataColumn);
                if (count > 0)
                {
                    result.Data = ids;
                }
            }
            return result;
        }

        /// <summary>
        /// 批量保存
        /// </summary>
        /// <param name="model"></param>
        /// <param name="currentUser"></param>
        /// <returns></returns>
        public virtual async ValueTask<ResponseContext<bool>> Saves(SavaListModel<TDto> model, UserTicket currentUser)
        {
            var result = new ResponseContext<bool>();

            if (model.Dtos == null || model.Dtos.Count == 0)
                return result;

            var entities = new List<TEntity>();
            foreach (var item in model.Dtos)
            {
                long id = GetId(item);
                if (id == 0)//新增
                {
                    var check = await AddValidate(item);
                    if (!check.IsSuccess)
                    {
                        continue;
                    }
                }
                else//修改
                {
                    var check = await UpdateValidate(item);
                    if (!check.IsSuccess)
                        return result.SetError(check);
                }

                var entity = item.MapTo<TEntity>();

                // 处理dto JOSN转string保存
                if (CommonService.IsJsonField(item))
                {
                    CommonService.LoadFieldsJsonCovertString(entity, item);
                }

                SetCommonProperty(entity, currentUser);
                entities.Add(entity);
            }

            var dataColumn = CommonService.GetEntityDataColumn<TEntity>();

            // 插入更新，存在更新，不存在插入
            int count = entities.Upsert(dataColumn);
            result.Data = count > 0;
            return await Task.FromResult(result);
        }

        /// <summary>
        /// 批量树结构保存并更新
        /// </summary>
        /// <param name="model"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public virtual async ValueTask<ResponseContext<bool>> SaveTreeList(SavaListModel<TreeBaseDto> model, UserTicket user)
        {
            var response = new ResponseContext<bool>();

            if (model.Dtos == null || model.Dtos.Count() == 0) return response;

            var entitys = new List<TEntity>();
            foreach (var item in model.Dtos)
            {
                long id = GetId(item);
                if (id == 0)//新增
                {
                    var entity = item.MapTo<TEntity>();
                    SetCommonProperty(entity, user);

                    SetCyxyCaseId(entity, model.Params);

                    entitys.Add(entity);

                    if (CommonService.CheckField<TEntity>("ParentId"))
                    {
                        var children = GetChildren(item);
                        if (children != null)
                        {
                            var parentid = CommonService.SetId(entity);

                            // 判断是否是树形结构数据
                            CommonService.SetPath(entity, parentid.ToString());

                            var path = CommonService.GetPath(entity);
                            await Children(children, parentid, path, user, entitys, model.Params);
                        }
                    }
                }
                else//修改
                {
                    var update = item.MapTo<TEntity>();
                    CommonService.SetUpdateTime(update);
                    CommonService.SetUpdateBy(update, user.Id);

                    SetCyxyCaseId(update, model.Params);

                    entitys.Add(update);

                    if (CommonService.CheckField<TEntity>("ParentId"))
                    {
                        var children = GetChildren(item);
                        if (children != null)
                        {
                            var parentid = CommonService.SetId(update);
                            var path = CommonService.GetPath(update);
                            // 判断是否是树形结构数据
                            CommonService.SetPath(update, parentid.ToString());
                            await Children(children, parentid, path, user, entitys, model.Params);
                        }
                    }
                }
            }

            var dataColumn = CommonService.GetEntityDataColumn<TEntity>();
            // 插入更新，存在更新，不存在插入
            int result = entitys.Upsert(dataColumn);
            response.Data = result > 0;
            return await Task.FromResult(response);
        }

        /// <summary>
        /// 递归保存树形结构数据
        /// </summary>
        /// <param name="childrens"></param>
        /// <param name="parentId"></param>
        /// <param name="path"></param>
        /// <param name="user"></param>
        /// <param name="entitys"></param>
        /// <param name="modelParams"></param>
        /// <returns></returns>
        public virtual async ValueTask<ResponseContext<bool>> Children(IEnumerable<TreeBaseDto> childrens, long parentId, string path, UserTicket user, List<TEntity> entitys, IDictionary<string, object> modelParams = null)
        {
            var response = new ResponseContext<bool>();
            foreach (var item in childrens)
            {
                long id = GetId(item);

                if (id == 0)//新增
                {
                    var entity = item.MapTo<TEntity>();

                    SetCommonProperty(entity, user);
                    //设置父级节点Id
                    CommonService.SetParentId(entity, parentId);

                    SetCyxyCaseId(entity, modelParams);

                    entitys.Add(entity);

                    // 判断是否是树形结构数据
                    //var parentid = CommonService.SetId(entity);
                    //父Id+当前Id;
                    var currId = CommonService.SetId(entity);
                    var allPath = path + currId;
                    CommonService.SetPath(entity, allPath);
                    var children = GetChildren(item);
                    if (children != null)
                    {
                        var nextPath = CommonService.GetPath(entity);
                        await this.Children(children, currId, nextPath, user, entitys, modelParams);
                    }
                }
                else//修改
                {
                    var update = item.MapTo<TEntity>();
                    CommonService.SetUpdateTime(update);
                    CommonService.SetUpdateBy(update, user.Id);

                    SetCyxyCaseId(update, modelParams);

                    //设置父级节点Id
                    CommonService.SetParentId(update, parentId);
                    entitys.Add(update);
                }
                //var field = Entity<TEntity>.Meta.Table.FindByName("ParentId");
            }
            // 插入更新，存在更新，不存在插入
            //int result = entitys.Upsert();
            //response.Data = result > 0;
            return await Task.FromResult(response);
        }

        /// <summary>
        ///
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="Params"></param>
        private void SetCyxyCaseId(TEntity entity, IDictionary<string, object> Params = null)
        {
            if (!Params.IsNullOrEmpty())
            {
                if (CommonService.CheckField<TEntity>("CyxyCaseId"))
                {
                    CommonService.SetProperty(entity, "CyxyCaseId", Params["CyxyCaseId"].ToLong());
                }
            }
        }

        /// <summary>
        /// 新增单个
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public virtual async ValueTask<ResponseContext<long>> Add(TDto dto, UserTicket user)
        {
            var result = new ResponseContext<long>();

            var check = await AddValidate(dto);
            if (!check.IsSuccess)
                return result.SetError(check);

            var entity = dto.MapTo<TEntity>();

            // 处理dto JOSN转string保存
            if (CommonService.IsJsonField(dto))
            {
                CommonService.LoadFieldsJsonCovertString(entity, dto);
            }
            long Id = SetCommonProperty(entity, user);//设置 TEntity 通用字段

            if (entity == null) { result.SetError("对象转换错误"); }

            bool b = await OnInsert(entity) > 0;
            return result.SetSuccess(Id);
        }

        /// <summary>
        /// </summary>
        /// <param name="dto"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public virtual async ValueTask<ResponseContext<bool>> Update(TDto dto, UserTicket user)
        {
            var result = new ResponseContext<bool>();
            var check = await UpdateValidate(dto);
            if (!check.IsSuccess)
                return result.SetError(check);

            var entity = dto.MapTo<TEntity>();

            // 处理dto JOSN转string保存
            if (CommonService.IsJsonField(dto))
            {
                CommonService.LoadFieldsJsonCovertString(entity, dto);
            }


            CommonService.SetCommonPropertyTenantId(entity, user);

            //CommonService.SetUpdateTime(entity);

            //CommonService.SetUpdateBy(entity, user.Id);

            await OnUpdate(entity);

            return result.SetSuccess(true);
        }

        /// <summary>
        /// 删除
        /// </summary>
        /// <param name="id"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public virtual async ValueTask<ResponseContext<bool>> Delete(long id, UserTicket user)
        {
            var result = new ResponseContext<bool>();
            var resp = await DeleteObject(id, user);
            if (resp.IsSuccess)
                return result.SetSuccess(true);
            else
                return result.SetError(resp);
        }

        /// <summary>
        /// 删除 返回删除的对象
        /// </summary>
        /// <param name="id"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        protected async ValueTask<ResponseContext<TEntity>> DeleteObject(long id, UserTicket user)
        {
            var entity = Entity<TEntity>.FindByKey(id);
            if (entity == null) return new ResponseContext<TEntity>(CommonConstants.BadRequest, "没有找到数据");
            // var delentity = entity.MapTo<TEntity>(); SetIsDelete(entity, 1);
            bool result;
            if (CommonService.CheckField<TEntity>("IsDelete"))//逻辑删除
            {
                SetIsDelete(entity, 1);
                CommonService.SetUpdateBy(entity, user.Id);
                CommonService.SetUpdateTime(entity);
                result = await OnUpdate(entity, true) > 0;
            }
            else//物理删除
            {
                result = await OnDelete(entity) > 0;
            }

            return new ResponseContext<TEntity> { Data = entity };
        }

        /// <summary>
        /// 批量删除
        /// </summary>
        /// <param name="ids"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public virtual async ValueTask<ResponseContext<bool>> DeleteIds(IEnumerable<long> ids, UserTicket user)
        {
            if (!ids.Any())
            {
                return new ResponseContext<bool>(CommonConstants.BadRequest, "参数不能为空！");
            }
            //if (user.UserType == UserTypeEnums.Admin || user.UserType == UserTypeEnums.Professional)
            //{
            foreach (var item in ids)
            {
                var entity = Entity<TEntity>.FindByKey(item);

                if (entity == null)
                    continue;
                if (CommonService.CheckField<TEntity>("IsDelete"))
                {
                    SetIsDelete(entity, 1);
                    CommonService.SetUpdateBy(entity, user.Id);
                    CommonService.SetUpdateTime(entity);
                    await OnUpdate(entity, true);
                }
                else//物理删除
                {
                    await OnDelete(entity);
                }
            }
            //}
            //else
            //{
            //    return new ResponseContext<bool>(CommonConstants.BadRequest, "非管理员和专业组帐号权限,不能使用批量删除！");
            //}
            return new ResponseContext<bool> { Data = true };
        }

        /// <summary>
        /// 查找单行数据
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public virtual TDto FindByID(long ID)
        {
            TEntity entity = Entity<TEntity>.FindByKeyForEdit(ID);

            // 处理dto JOSN转string保存
            //if (CommonService.IsJsonField(result))
            //{
            //    CommonService.LoadFieldsStringCovertJson(entity, result);
            //}
            return entity.MapTo<TDto>();
        }

        /// <summary>
        /// 根据Id查询数据
        /// </summary>
        /// <param name="Id"></param>
        /// <returns></returns>
        public virtual async Task<ResponseContext<TDto>> FindById(long Id)
        {
            TDto result = null;
            var field = Entity<TEntity>.Meta.Table.FindByName("Id");
            var where = new WhereExpression();
            where &= field == Id;
            var entity = await Entity<TEntity>.FindAsync(where);
            if (entity != null)
            {
                result = entity.MapTo<TDto>();

                // 处理dto JOSN转string保存
                if (CommonService.IsJsonField(result))
                {
                    CommonService.LoadFieldsStringCovertJson(entity, result);
                }

            }
            return new ResponseContext<TDto> { Data = result };
        }

        /// <summary>
        /// 按条件查询 单条信息
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public virtual async Task<ResponseContext<TDto>> FindBy(RequestParameter p)
        {
            var result = new ResponseContext<TDto>();
            if (p.Params == null || p.Params.Count == 0)
                return result.SetError("请设置查询条件。");
            TDto dto = null;

            var whereExpression = CommonService.BuildWhereExpression<TEntity>(p.Params);//构建查询条件

            var entity = await Entity<TEntity>.FindAsync(whereExpression);
            if (entity != null)
            {
                dto = entity.MapTo<TDto>();

                // 处理dto JOSN转string保存
                if (CommonService.IsJsonField(dto))
                {
                    CommonService.LoadFieldsStringCovertJson(entity, dto);
                }

            }

            return result.SetSuccess(dto);
        }

        /// <summary>
        /// 导入数据(通用的导入数据)
        /// </summary>
        /// <param name="file"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public async ValueTask<bool> ImportDate<T>(IFormFile file, UserTicket user) where T : class, new()
        {
            var result = false;
            using (var ms = file.OpenReadStream())
            {
                var datas = await ms.QueryAsync<T>();

                var entitys = new List<TEntity>();

                foreach (var item in datas)
                {
                    var entity = item.MapTo<TEntity>();
                    SetCommonProperty(entity, user);
                    entitys.Add(entity);
                }
                ;

                var dataColumn = CommonService.GetEntityDataColumn<TEntity>();

                // 插入更新，存在更新，不存在插入
                result = entitys.Upsert(dataColumn) > 0;
            }
            return await Task.FromResult(result);
        }

        /// <summary>
        /// 导出实体模版
        /// </summary>
        /// <returns></returns>
        public virtual async ValueTask<MemoryStream> DownloadTemplate()
        {
            DataTable values = new DataTable();
            foreach (var item in Entity<TEntity>.Meta.AllFields)
            {
                values.Columns.Add(item.Description);
            }
            var t = new TableStyles { };
            var config = new OpenXmlConfiguration
            {
                AutoFilter = false,
                TableStyles = TableStyles.Default
            };
            var memoryStream = new MemoryStream();
            memoryStream.SaveAs(values, sheetName: Entity<TEntity>.Meta.TableName, configuration: config);
            memoryStream.Seek(0, SeekOrigin.Begin);
            return await Task.FromResult(memoryStream);
        }

        //protected virtual Task<int> OnInsert(TEntity entity) => entity.InsertAsync();

        protected virtual Task<int> OnInsert(TEntity entity)
        {
            return Task.FromResult(entity.Upsert(GetEntityDataColumn<TEntity>()));
        }

        /// <summary>
        /// 更新实体对象
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="isDelete"></param>
        /// <returns></returns>
        // protected virtual Task<int> OnUpdate(TEntity entity) => entity.UpdateAsync();

        protected virtual Task<int> OnUpdate(TEntity entity, bool isDelete = false)
        {
            var fs = GetFields(entity.GetType());
            // 脏数据是生成Update语句的核心，不脏的字段不会出现在update set 之中，从而实现部分字段更新。
            // 设置忽略更新，设置字段为不脏
            SetNoDirtyItem(fs, entity, CommonColumns.TenantId);
            SetNoDirtyItem(fs, entity, CommonColumns.CreateBy);
            SetNoDirtyItem(fs, entity, CommonColumns.CreateTime);

            if (!isDelete)
                SetNoDirtyItem(fs, entity, CommonColumns.IsDelete);

            return Task.FromResult(entity.Upsert(GetEntityDataColumn<TEntity>()));
        }

        /// <summary>设置脏数据项。如果某个键存在并且数据没有脏，则设置</summary>
        /// <param name="fields"></param>
        /// <param name="entity"></param>
        /// <param name="name"></param>
        /// <returns>返回是否成功设置了数据</returns>
        protected virtual Boolean SetNoDirtyItem(ICollection<FieldItem> fields, IEntity entity, String name)
        {
            var fi = fields.FirstOrDefault(e => e.Name.EqualIgnoreCase(name));
            if (fi == null)
            {
                return false;
            }
            name = fi.Name;
            entity.Dirtys[name] = false;
            return entity.IsDirty(name);
        }

        /// <summary>获取实体类的字段名。带缓存</summary>
        /// <param name="entityType"></param>
        /// <returns></returns>
        protected static FieldItem[] GetFields(Type entityType) => CommonService._fields.GetOrAdd(entityType, t => t.AsFactory().Fields);

        /// <summary>
        /// 删除实体对象
        /// </summary>
        /// <param name="entity"></param>
        /// <returns></returns>
        protected virtual Task<int> OnDelete(TEntity entity) => entity.DeleteAsync();

        /// <summary>
        /// 设置 TEntity 通用字段
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public long SetCommonProperty<T>(T entity, UserTicket user) where T : Entity<T>, new()
        {
            return CommonService.SetCommonProperty(entity, user);
        }

        /// <summary>
        /// 设置主键
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        private long GetId(TDto dto)
        {
            long id = 0;
            Type type = dto.GetType();
            PropertyInfo pi = type.GetProperty("Id");
            var idAny = pi.GetValue(dto);
            if (idAny.ToLong() > 0)
                id = idAny.ToLong();
            return id;
        }

        /// <summary>
        /// 设置主键
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        private long GetId(TreeBaseDto dto)
        {
            long id = 0;
            Type type = dto.GetType();
            PropertyInfo pi = type.GetProperty("Id");
            var idAny = pi.GetValue(dto);
            if (idAny.ToLong() > 0)
                id = idAny.ToLong();
            return id;
        }

        /// <summary>
        /// 判断是否有子集
        /// </summary>
        /// <param name="dto"></param>
        /// <returns></returns>
        private dynamic GetChildren(TreeBaseDto dto)
        {
            Type type = dto.GetType();
            PropertyInfo pi = type.GetProperty("Children");
            if (pi == null) return null;
            var idAny = pi.GetValue(dto);
            return idAny;
        }

        /// <summary>
        /// </summary>
        /// <param name="entity"></param>
        /// <param name="IsDelete"></param>
        /// <exception cref="Exception"></exception>
        protected void SetIsDelete(TEntity entity, int IsDelete)
        {
            string name = "IsDelete";
            Type type = entity.GetType();
            PropertyInfo pi = type.GetProperty(name);
            if (pi != null)
                pi.SetValue(entity, IsDelete);
            else
            {
                throw new Exception($"不能使用该接口进行逻辑删除，该对象{type.Name}不支持逻辑删除。");
            }
        }
    }
}